package com.mxx.common.http;

import com.mxx.common.utils.InputStreamUtil;
import com.mxx.common.utils.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.springframework.util.ClassUtils;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Slf4j
public class ApacheHttpUtil {

    public static RequestConfig config = getConfig();

    public static com.mxx.common.http.ApacheHttpResponse doPost(String url, String content, Charset charset) throws com.mxx.common.exception.IOException {
        return ApacheHttpResponse.read(doPostOfJson(url, content, Collections.EMPTY_MAP, charset));
    }

    public static com.mxx.common.http.ApacheHttpResponse doPost(String url, String content, Map<String, String> headers, Charset charset) throws com.mxx.common.exception.IOException {
        return ApacheHttpResponse.read(doPostOfJson(url, content, headers, charset));
    }

    public static com.mxx.common.http.ApacheHttpResponse doPostForm(String url, Map<?, ?> formData, Charset charset) throws com.mxx.common.exception.IOException {
        return ApacheHttpResponse.read(doPostOfForm(url, formData, Collections.EMPTY_MAP, charset));
    }

    public static com.mxx.common.http.ApacheHttpResponse doPostForm(String url, Map<?, ?> formData, Map<String, String> headers, Charset charset) throws com.mxx.common.exception.IOException {
        return ApacheHttpResponse.read(doPostOfForm(url, formData, headers, charset));
    }

    public static com.mxx.common.http.ApacheHttpResponse doGet(String url, Map<?, ?> map) throws com.mxx.common.exception.IOException {
        return ApacheHttpResponse.read(executeGet(url, map, Collections.EMPTY_MAP));
    }

    public static com.mxx.common.http.ApacheHttpResponse doGet(String url, Map<?, ?> map, Map<String, String> headerData) throws com.mxx.common.exception.IOException {
        return ApacheHttpResponse.read(executeGet(url, map, headerData));
    }


    public static HttpResponse doPostOfJson(String url, String jsonStr, Map<String, String> headerData, Charset charset) throws com.mxx.common.exception.IOException {
        HttpEntity entity = null;
        if (jsonStr != null && !jsonStr.equals("")) {
            entity = new StringEntity(jsonStr, charset);
        }
        return executePost(url, entity, headerData);
    }

    public static HttpResponse doPostOfForm(String url, Map<?, ?> formData, Map<String, String> headerData, Charset charset) throws com.mxx.common.exception.IOException {
        HttpEntity entity = null;
        List<NameValuePair> nameValuePairList = new ArrayList<>();
        for (Map.Entry<?, ?> entry : formData.entrySet()) {
            String str = entry.getValue() == null ? null : entry.getValue().toString();
            nameValuePairList.add(new BasicNameValuePair(entry.getKey().toString(), str));
        }
        if (!nameValuePairList.isEmpty()) {
            entity = new UrlEncodedFormEntity(nameValuePairList, charset);
        }
        return executePost(url, entity, headerData);
    }


    /**
     * @param url        请求的url
     * @param entity     JSON数据
     * @param headerData 请求头
     * @return HttpEntity 返回数据流
     * @throws Exception
     */
    public static HttpResponse executePost(String url, HttpEntity entity, Map<String, String> headerData) throws com.mxx.common.exception.IOException {
        HttpPost httpPost = new HttpPost(url);
        if (entity != null) {
            httpPost.setEntity(entity);
        }
        setHeader(httpPost, headerData);
        return execute(httpPost, config);
    }

    public static HttpResponse executeGet(String url, Map<?, ?> map, Map<String, String> headerData) throws com.mxx.common.exception.IOException {
        url = Strings.url(url, map);
        HttpRequestBase requestBase = new HttpGet(url);
        setHeader(requestBase, headerData);
        return execute(requestBase, config);
    }

    public static HttpResponse execute(HttpRequestBase requestBase, RequestConfig requestConfig) throws com.mxx.common.exception.IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        requestBase.setConfig(requestConfig);
        try {
            return httpClient.execute(requestBase);
        } catch (IOException e) {
            String error = String.format(" read inputStream exception :{url:%s,exName:%s,msg:%s}", requestBase.getURI().getPath(), ClassUtils.getQualifiedName(e.getClass()), e.getMessage());
            throw new com.mxx.common.exception.IOException(e, error);
        }
    }

    public static RequestConfig getConfig() {
        return RequestConfig.custom()
                .setConnectTimeout(5000).setConnectionRequestTimeout(5000)
                .setSocketTimeout(5000).build();
    }

    private static void setHeader(HttpRequestBase requestBase, Map<String, String> headerData) {
        for (Map.Entry<String, String> entry : headerData.entrySet()) {
            requestBase.setHeader(entry.getKey(), entry.getValue());
        }
    }

    private static String readHttpResponse(HttpResponse response) throws com.mxx.common.exception.IOException {
        HttpEntity httpEntity = response.getEntity();
        String encoding;
        if (httpEntity.getContentEncoding() == null) {
            encoding = "UTF-8";
        } else {
            encoding = httpEntity.getContentEncoding().getValue();
        }
        try {
            return InputStreamUtil.read(httpEntity.getContent(), Charset.forName(encoding)).toString();
        } catch (Exception e) {
            String error = String.format(" read inputStream exception :{exName:%s,msg:%s}", ClassUtils.getQualifiedName(e.getClass()), e.getMessage());
            throw new com.mxx.common.exception.IOException(e, error);
        }
    }
}
